/**
 * 
 */
package com.feib.soeasy.job;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;

import net.sourceforge.stripes.action.FileBean;
import net.sourceforge.stripes.mock.MockHttpServletRequest;
import net.sourceforge.stripes.mock.MockHttpServletResponse;
import net.sourceforge.stripes.mock.MockHttpSession;
import net.sourceforge.stripes.mock.MockServletContext;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import com.feib.soeasy.action.BaseActionBeanContext;
import com.feib.soeasy.action.Soez1012ActionBean;
import com.feib.soeasy.job.service.AutoUploadCarLoanFileService;
import com.feib.soeasy.job.util.AutoUploadCarLoanFileMailContent;
import com.feib.soeasy.model.CodeTable;
import com.feib.soeasy.model.FormatDefinition;
import com.feib.soeasy.model.Group;
import com.feib.soeasy.model.MailQueue;
import com.feib.soeasy.model.User;
import com.feib.soeasy.security.SoeasyUserDetails;
import com.feib.soeasy.service.AsyncService;
import com.feib.soeasy.service.GroupService;
import com.feib.soeasy.service.UploadFileService;
import com.feib.soeasy.service.UserService;
import com.feib.soeasy.util.UserUtil;

/**
 * @author Jimmy Liu
 * @memo 只會做系統日的Check&NonCheck，其他日期的不吃
 * @memo 指定要吃的檔案一定都要到齊做完才會回寫日期(但先執行的Group檔案若沒問題，可能會已先上傳成功)
 * @memo 不管怎樣，就算先執行的Group已先上傳，下次再做就會檢查到已上傳不做
 * @memo 總之要最後執行的Group執行完才會回寫日期 
 */
@Service("autoUploadCarLoanFileJob")
public class AutoUploadCarLoanFileJob implements Serializable  {

	private static final long serialVersionUID = 1L;

	public static Logger logger = LoggerFactory.getLogger(AutoUploadCarLoanFileJob.class);

	private static final String CAR_LOAN_JOB_KEY = "CARLOANJOB";

	private static final String UPLOAD_USERID_KEY = CAR_LOAN_JOB_KEY + "_UPLOAD_USERID";
	private static final String CART_LOAN_FILE_NAME_KEY = CAR_LOAN_JOB_KEY + "_FILENAME";
	private static final String CART_LOAN_FILE_FORMAT_KEY = CAR_LOAN_JOB_KEY + "_FILE_FORMAT";

	private static final String CART_LOAN_FTP_SERVER_IP_KEY = CAR_LOAN_JOB_KEY + "_FTP_SVR_IP";
	private static final String CART_LOAN_FTP_SERVER_PORT_KEY = CAR_LOAN_JOB_KEY + "_FTP_SVR_PORT";
	private static final String CART_LOAN_FTP_USER_NAME_KEY = CAR_LOAN_JOB_KEY + "_FTP_USER_NAME";
	private static final String CART_LOAN_FTP_USER_PASSWORD_KEY = CAR_LOAN_JOB_KEY + "_FTP_PASSWORD";
	private static final String CART_LOAN_FTP_REMOTE_FOLDER_KEY = CAR_LOAN_JOB_KEY + "_FTP_REMOTE_DIR";
	private static final String CART_LOAN_FTP_RETRY_TIMES_KEY = CAR_LOAN_JOB_KEY + "_FTP_RETRY";

	@Resource(name="userService")
	private UserService userService;

	@Resource(name="groupService")
	private GroupService groupService;

	@Resource(name="uploadFileService")
	private UploadFileService uploadFileService;

	@Resource(name="fileImportDestination")
	private String fileImportDestination;

	@Resource(name="fileDownloadDestination")
	private String fileDownloadDestination;

	@Resource(name="txManager")
	private PlatformTransactionManager transactionManager;

	@Resource(name="itEmails")
	private String itEmails;

	@Resource(name="mailJob")
	private MailJob mailJob;

	@Resource(name="htmlMailFolder")
	private String htmlMailFolder;

	@Resource(name="defaultMailFrom")
	private String defaultMailFrom;

	@Resource(name="defaultMailReturnReceiptTo")
	private String defaultMailReturnReceiptTo;

	@Resource(name="syncServiceImpl")
	private AsyncService asyncService;

	@Resource(name="autoUploadCarLoanFileService")
	private AutoUploadCarLoanFileService autoUploadCarLoanFileService;

	private DateFormat yyyyMMddHHmmFormat = new SimpleDateFormat("yyyyMMdd HH:mm");

	private DateFormat yyyyMMddFormat = new SimpleDateFormat("yyyyMMdd");

	private DateFormat yyyyMMddFormat1 = new SimpleDateFormat("yyyy/MM/dd");

	private DateFormat hhmmFormat = new SimpleDateFormat("HHmm");

	private DateFormat hhmmFormat1 = new SimpleDateFormat("HH:mm");

	public void execute() throws Exception
	{
		//StringBuffer executeLogText = new StringBuffer();

		/* 每日啟動時間 (時:分), 在這時間後才可執行*/
		CodeTable startTimeCodeTable = autoUploadCarLoanFileService.getCodeTable(CAR_LOAN_JOB_KEY, "START_TIME");
		String dbStartTime = startTimeCodeTable.getCodeName(); //ex: 01:00
		/* 最後啟動日期，若當日有執行需更新執行日期 */
		CodeTable lastExecutedDateCodeTable = autoUploadCarLoanFileService.getCodeTable(CAR_LOAN_JOB_KEY, "LAST_EXECUTED_DATE");
		String dbLastExecutedDate = lastExecutedDateCodeTable.getCodeName(); // ex: 2012/09/24 

		/* 系統時間 */
		Date now = new Date();

		/*系統時間 (無時分秒)*/
		Date sysYyyyMMdd = yyyyMMddFormat.parse(yyyyMMddFormat.format(now));

		/* 今日啟動時間 */
		Date startYyyyMMddHHmm = yyyyMMddHHmmFormat.parse(yyyyMMddFormat.format(now) + " " + dbStartTime);

		/* 最後啟動日期 最後啟動日期*/
		Date lastExecutedDate = yyyyMMddFormat1.parse(dbLastExecutedDate); // 上次執行成功時間
		//String startTime = hhmmFormat.format(hhmmFormat1.parse(dbStartTime));

		/* 系統時間為2012-09-06 06:00 < 09:00則不執行 */
		if (now.compareTo(startYyyyMMddHHmm) < 0)
		{
			logger.info("[不執行]系統時間小於每日啟動時間");
		}
		else
		{	
			/* 若系統日期為2012-09-06且最後啟動日期為2012-09-06不執行 */
			if (sysYyyyMMdd.compareTo(lastExecutedDate) <= 0)
			{
				logger.info("[不執行]本日已執行過");
			}
			else
			{
				CodeTable groupNoCodeTable = autoUploadCarLoanFileService.getCodeTable(CAR_LOAN_JOB_KEY, "GROUP_NO");
				String[] groupNos = groupNoCodeTable.getCodeName().split(",");
				/* 系統日若不為營業日(參考中租現有批次程式可得知系統日是否為營業日)，則只更新最後啟動日期。 */
				boolean isHoliday = isHoliday(now);
				boolean needUpdRunDate = true;
				if (!isHoliday)
				{
					logger.info("本日為營業日, 需執行");
					StringBuffer logText = null;
					for(String groupNo :groupNos){
						logText = new StringBuffer();
						needUpdRunDate = doUpload(groupNo, now, logText);
						if (! needUpdRunDate)
						{
							/* 檔案上傳錯誤，需發送 logText*/
							failNotice(logText.toString(), now, groupNo);
							break;
						}
					}
				}
				else
				{
					logger.info("[不執行]本日為假日(只更新最後啟動日期)");
				}

				if (needUpdRunDate)
				{
					logger.info("更新最後啟動日期");
					updateLastExecutedDate(now);
				}
			}
		}
		//		UserUtil.setServletRequest(null);
		//        UserUtil.setServletResponse(null);
	}

	/**
	 * 是否為假日
	 * @param now
	 * @return
	 */
	private boolean isHoliday(Date now) {
		return autoUploadCarLoanFileService.isHoliday(now);
	}

	/**
	 * 更新最後啟動日期
	 * @param groupNo
	 */
	private void updateLastExecutedDate(Date now)
	{
		CodeTable lastExecutedDateCodeTable = autoUploadCarLoanFileService.getCodeTable(CAR_LOAN_JOB_KEY, "LAST_EXECUTED_DATE");
		lastExecutedDateCodeTable.setCodeName(yyyyMMddFormat1.format(now));
		autoUploadCarLoanFileService.updateRunDate(lastExecutedDateCodeTable);
	}

	public boolean doUpload(String groupNo, Date now, StringBuffer logText) throws Exception
	{
		// 模擬 ServletContext
		MockServletContext servletContext = new MockServletContext("autoUploadCarLoanFile");
		MockHttpSession session = new MockHttpSession(servletContext);
		MockHttpServletRequest request = new MockHttpServletRequest("autoUploadCarLoanFile", "Soez1012.action");
		request.setSession(session);
		MockHttpServletResponse response = new MockHttpServletResponse();

		UserUtil.setServletRequest(request);
		UserUtil.setServletResponse(response);

		// 設定上傳使用者 CarLoan Admin User
		String uploadGroupNo = groupNo;
		CodeTable uploadUserIdCodeTable = autoUploadCarLoanFileService.getCodeTable(UPLOAD_USERID_KEY, groupNo);
		String uploadUserId = uploadUserIdCodeTable.getCodeName(); // ex: "admin"
		User uploadUser = userService.loginByUerIdGroupNo(uploadUserId, uploadGroupNo);
		SoeasyUserDetails userWrapper = new SoeasyUserDetails(uploadUser);        
		UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userWrapper, "XXXXX");
		SecurityContextHolder.getContext().setAuthentication(authentication);

		CodeTable localFolderCodeTable = autoUploadCarLoanFileService.getCodeTable(CAR_LOAN_JOB_KEY, "LOCAL_FOLDER");
		String localFolder = localFolderCodeTable.getCodeName(); // ex: C:/

		CodeTable carLoanFileNameCodeTable = autoUploadCarLoanFileService.getCodeTable(CART_LOAN_FILE_NAME_KEY, groupNo);
		String[] fileNames = carLoanFileNameCodeTable.getCodeName().split(",");
		List<String> toDoFileNames = new ArrayList<String>(); // 需要做上傳轉入的檔名
		
		// ============ 取得 FTP 設定 ========
		// 取得 ftp host
		CodeTable hostCodeTable = autoUploadCarLoanFileService.getCodeTable(CART_LOAN_FTP_SERVER_IP_KEY, groupNo);
		String host = hostCodeTable.getCodeName();

		// 取得 ftp port
		CodeTable hostPortCodeTable = autoUploadCarLoanFileService.getCodeTable(CART_LOAN_FTP_SERVER_PORT_KEY, groupNo);
		int port = 21;
		if (null != hostPortCodeTable)
			port = Integer.parseInt(hostPortCodeTable.getCodeName());

		// 取得 ftp user name
		CodeTable userNameCodeTable = autoUploadCarLoanFileService.getCodeTable(CART_LOAN_FTP_USER_NAME_KEY, groupNo);
		String username = userNameCodeTable.getCodeName();

		// 取得 ftp user password
		CodeTable passwordCodeTable = autoUploadCarLoanFileService.getCodeTable(CART_LOAN_FTP_USER_PASSWORD_KEY, groupNo);
		String password = passwordCodeTable.getCodeName();

		// 取得 ftp 遠端目錄
		CodeTable remoteFolderCodeTable = autoUploadCarLoanFileService.getCodeTable(CART_LOAN_FTP_REMOTE_FOLDER_KEY, groupNo);
		String remoteFolder = remoteFolderCodeTable.getCodeName();

		// 取得 ftp 下載重做次數
		CodeTable retryCntCodeTable = autoUploadCarLoanFileService.getCodeTable(CART_LOAN_FTP_RETRY_TIMES_KEY, groupNo);
		int retryCnt = 1;
		if (null != retryCntCodeTable)
			retryCnt = Integer.parseInt(retryCntCodeTable.getCodeName());
		
		

		boolean isOk = true;
		
		for (int i=0; i < fileNames.length; i++)
		{
			/* 置換檔名，所以只會做當日檔 */
			fileNames[i] = fileNames[i] + "." + yyyyMMddFormat.format(now) + ".TXT"; //"CarLoan_upload.Check.20120802.TXT";
			
			/* 判斷 是否已上傳過，(排除刪除)*/
			if (this.autoUploadCarLoanFileService.hasUploadFile(groupNo, fileNames[i]))
			{
				// 已經上傳過了，不需要再轉入
				/*
				 * 只要確認當天的檔案都有上傳了，就可以回寫啟動日期，不繼續往下做
				 * 例如：啟動時發現NonCheck已經有同檔名檔案存在則不上傳，但Check如果沒有就要上傳，
				 * 回寫啟動日期；如果啟動時兩個當日日期檔都已存在，則直接回寫啟動日期，不作用。 
				 */
				toDoFileNames.add(null);
			}
			else
			{
				// 到這邊都是未上傳過檔案，已經在此mehod呼叫前就檢查了
				// 下載檔案
				isOk = this.autoUploadCarLoanFileService.retryGetFtpFile(
						host, port, username, password, localFolder
						, remoteFolder, fileNames[i], retryCnt);

				if (!isOk)
				{
					logger.info("[下載錯誤]檔案 {} 無法下載", fileNames[i]);
					logText.append("[下載錯誤]檔案 ").append(fileNames[i]).append(" 無法下載").append("\r\n");
				}
				else
				{
					File f = new File(localFolder + "/" + fileNames[i]);
					byte[] contents = FileUtils.readFileToByteArray(f);
					if (contents.length == 0)
					{
						/*
						 * 假如兩檔中有一檔是空檔，就只傳有資料的那個檔案，執行完直接回寫啟動日期。兩個都為空檔就直接回寫啟動日期就好。
						 */
						/*
						logger.info("[下載錯誤]檔案 {} 為空檔",sFileName);
						logText.append("[下載錯誤]檔案 ").append(sFileName).append(" 為空檔").append("\r\n");
						contents = null;
						break;
						*/
						logger.info("檔案 {} 為空檔, 不需要上傳檔案",fileNames[i]);
						toDoFileNames.add(null);
					}
					else
					{
						logger.info("檔案 {} 已下載, 需要上傳檔案",fileNames[i]);
						toDoFileNames.add(fileNames[i]);
					}
					contents = null;
				}
			}
		}


		if (!isOk)
			return false;


		CodeTable carLoanFileFormatCodeTable = autoUploadCarLoanFileService.getCodeTable(CART_LOAN_FILE_FORMAT_KEY, groupNo);
		String[] fileFormats = carLoanFileFormatCodeTable.getCodeName().split(",");

		for (int i=0; i < fileNames.length; i++)
		{
			if (null == toDoFileNames.get(i))
				continue;  //代表已經上傳過，或是空檔
			
			String carLoanFileName = fileNames[i];			
			String path = localFolder + "/" + carLoanFileName;
			Long formatDefinitionPk = new Long(fileFormats[i]);//new Long(1); 檔案格式


			// 模擬Soez1012ActionBean 上傳
			BaseActionBeanContext actionBeanContext = new BaseActionBeanContext();
			actionBeanContext.setServletContext(servletContext);
			actionBeanContext.setRequest(request);
			actionBeanContext.setResponse(response);
			Soez1012ActionBean actionBean = new Soez1012ActionBean();
			actionBean.setContext(actionBeanContext);
			actionBean.setGroupService(groupService);
			actionBean.setUploadFileService(uploadFileService);

			// 上傳檔案
			FileBean filedata = new FileBean(new File(path), "text", carLoanFileName);
			actionBean.setFiledata(filedata);
			// 上傳人員與群組
			actionBean.getUploadFile().setUploadUser(uploadUser);
			actionBean.getUploadFile().setGroup(uploadUser.getGroup());
			// 上傳格式
			FormatDefinition formatDefinition = new FormatDefinition();
			formatDefinition.setFormatDefinitionPk(formatDefinitionPk);
			actionBean.getUploadFile().setFormatDefinition(formatDefinition);

			// 檢核程式
			actionBean.setAsyncService(asyncService);

			actionBean.setFileDownloadDestination(fileDownloadDestination);
			actionBean.setFileImportDestination(fileImportDestination);

			actionBean.doUpload();
		}

		return true;

	}
	

//	private boolean downloadFiles(String groupNo, String[] fileNames, String localFolder, StringBuffer logText) throws Exception
//	{
//
//		// 取得 ftp host
//		CodeTable hostCodeTable = autoUploadCarLoanFileService.getCodeTable(CART_LOAN_FTP_SERVER_IP_KEY, groupNo);
//		String host = hostCodeTable.getCodeName();
//
//		// 取得 ftp port
//		CodeTable hostPortCodeTable = autoUploadCarLoanFileService.getCodeTable(CART_LOAN_FTP_SERVER_PORT_KEY, groupNo);
//		int port = 21;
//		if (null != hostPortCodeTable)
//			port = Integer.parseInt(hostPortCodeTable.getCodeName());
//
//		// 取得 ftp user name
//		CodeTable userNameCodeTable = autoUploadCarLoanFileService.getCodeTable(CART_LOAN_FTP_USER_NAME_KEY, groupNo);
//		String username = userNameCodeTable.getCodeName();
//
//		// 取得 ftp user password
//		CodeTable passwordCodeTable = autoUploadCarLoanFileService.getCodeTable(CART_LOAN_FTP_USER_PASSWORD_KEY, groupNo);
//		String password = passwordCodeTable.getCodeName();
//
//		// 取得 ftp 遠端目錄
//		CodeTable remoteFolderCodeTable = autoUploadCarLoanFileService.getCodeTable(CART_LOAN_FTP_REMOTE_FOLDER_KEY, groupNo);
//		String remoteFolder = remoteFolderCodeTable.getCodeName();
//
//		// 取得 ftp 下載重做次數
//		CodeTable retryCntCodeTable = autoUploadCarLoanFileService.getCodeTable(CART_LOAN_FTP_RETRY_TIMES_KEY, groupNo);
//		int retryCnt = 1;
//		if (null != retryCntCodeTable)
//			retryCnt = Integer.parseInt(retryCntCodeTable.getCodeName());
//
//		boolean isOk = true;
//		for (String sFileName: fileNames)
//		{
//			/* 是否已上傳過，(排除刪除)*/
//			isOk = !this.autoUploadCarLoanFileService.hasUploadFile(groupNo, sFileName);
//			if (!isOk)
//			{
//				/*
//				 * 只要確認當天的檔案都有上傳了，就可以回寫啟動日期，不繼續往下做
//				 * 例如：啟動時發現NonCheck已經有同檔名檔案存在則不上傳，但Check如果沒有就要上傳，
//				 * 回寫啟動日期；如果啟動時兩個當日日期檔都已存在，則直接回寫啟動日期，不作用。 
//				 */
//				/*
//				logger.info("[下載錯誤]檔案 {} 已上傳",sFileName);
//				logText.append("[下載錯誤]檔案 ").append(sFileName).append(" 已上傳").append("\r\n");
//				break;
//				*/
//				logger.info("檔案 {} 已上傳, 不用再做轉入動作",sFileName);
//			}
//			else
//			{
//				// 未上傳過檔案
//				isOk = this.autoUploadCarLoanFileService.retryGetFtpFile(
//						host, port, username, password, localFolder
//						, remoteFolder, sFileName, retryCnt);
//
//				if (!isOk)
//				{
//					logger.info("[下載錯誤]檔案 {} 無法下載",sFileName);
//					logText.append("[下載錯誤]檔案 ").append(sFileName).append(" 無法下載").append("\r\n");
//					break;
//				}
//				else
//				{
//					File f = new File(localFolder + "/" + sFileName);
//					byte[] contents = FileUtils.readFileToByteArray(f);
//					isOk = (contents.length != 0);
//					if (!isOk)
//					{
//						/*
//						 * 假如兩檔中有一檔是空檔，就只傳有資料的那個檔案，執行完直接回寫啟動日期。兩個都為空檔就直接回寫啟動日期就好。
//						 */
//						/*
//						logger.info("[下載錯誤]檔案 {} 為空檔",sFileName);
//						logText.append("[下載錯誤]檔案 ").append(sFileName).append(" 為空檔").append("\r\n");
//						contents = null;
//						break;
//						*/
//						logger.info("檔案 {} 為空檔",sFileName);
//					}
//					else
//					{
//						logger.info("檔案 {} 已下載",sFileName);
//					}
//					contents = null;
//				}
//			}
//		}
//
//
//		return isOk;
//	}

	/**
	 * 系統錯誤通知
	 * @param e
	 * @throws IOException 
	 */
	public void exceptionNotice(Exception e, Date now) throws IOException
	{
		if (null == e)
			return ;

		// 沒有設定 IT EMALS
		if (StringUtils.isEmpty(itEmails))
		{
			logger.error("因為沒有設定 IT Email，導致無法發送錯誤訊息給IT");
			logger.error("系統錯誤如下", e);
			return ;
		}

		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");

		StringWriter sw = new StringWriter();
		PrintWriter pw = new PrintWriter(sw);
		e.printStackTrace(pw);

		String exceptionMessage = sw.toString();

		String messageTile = "[全方位企業收款服務] 中租帳單自動上傳失敗";
		StringBuffer paragraph1 = new StringBuffer();
		paragraph1.append("中租帳單自動上傳批次 於 ").append(dateFormat.format(now));
		paragraph1.append("執行上傳檔案 , 轉入時發生系統錯誤。");
		String[] paragraphs = new String[]{"您好", paragraph1.toString()};
		AutoUploadCarLoanFileMailContent mailContent = new AutoUploadCarLoanFileMailContent(messageTile, paragraphs, htmlMailFolder);
		mailContent.setExceptionMessage(exceptionMessage);

		MailQueue mailQueue = mailContent.createMailQueue();
		mailQueue.setMailTo(itEmails);
		mailQueue.setMailFrom(defaultMailFrom);
		mailQueue.setMailReturnReceiptTo(defaultMailReturnReceiptTo);

		// 建立交易的定義，每一次都是新的 Transaction
		DefaultTransactionDefinition definition = new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
		TransactionStatus status = this.transactionManager.getTransaction(definition);
		try {
			this.autoUploadCarLoanFileService.addMailQueue(mailQueue);
		}
		catch (Exception e2) {

			logger.error(e2.getMessage(),  e2);

			transactionManager.rollback(status);
			status = null; // roll back 不需要再呼叫 commit
		}
		if (null != status)
			transactionManager.commit(status);

		// 立即發送
		logger.debug("立即發送 Mail 給  {}", itEmails);
		mailJob.execute(mailQueue.getMailQueuePk());
		mailQueue = null; // free resource
	}

	/**
	 * 失敗通知
	 * @param groupNo TODO
	 * @throws IOException 
	 */
	protected void failNotice(String msg, Date now, String groupNo) throws Exception
	{
		if (null == msg)
			return ;

		// 沒有設定 IT EMALS
		if (StringUtils.isEmpty(itEmails))
		{
			logger.error("因為沒有設定 IT Email，導致無法發送失敗訊息給IT");
			logger.info("失敗通知訊息如下{}", msg);
			return ;
		}

		/* 區分業者 */
		Group group=groupService.findByExactGroupNo(groupNo);
		String groupName=group.getGroupName();
				
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");

		String messageTile = "[全方位企業收款服務] "+groupName+"帳單自動上傳失敗";
		StringBuffer paragraph1 = new StringBuffer();
		paragraph1.append(groupName).append("帳單自動上傳批次 於 ").append(dateFormat.format(now));
		paragraph1.append("執行上傳檔案 , 轉入失敗。");
		String[] paragraphs = new String[]{"您好", paragraph1.toString()};
		AutoUploadCarLoanFileMailContent mailContent = new AutoUploadCarLoanFileMailContent(messageTile, paragraphs, htmlMailFolder);
		mailContent.setOtherContent(msg);

		MailQueue mailQueue = mailContent.createMailQueue();
		mailQueue.setMailTo(itEmails);
		mailQueue.setMailFrom(defaultMailFrom);
		mailQueue.setMailReturnReceiptTo(defaultMailReturnReceiptTo);

		// 建立交易的定義，每一次都是新的 Transaction
		DefaultTransactionDefinition definition = new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
		TransactionStatus status = this.transactionManager.getTransaction(definition);
		try {
			this.autoUploadCarLoanFileService.addMailQueue(mailQueue);
		}
		catch (Exception e2) {

			logger.error(e2.getMessage(),  e2);

			transactionManager.rollback(status);
			status = null; // roll back 不需要再呼叫 commit
		}
		if (null != status)
			transactionManager.commit(status);

		// 立即發送
		logger.debug("立即發送 Mail 給  {}", itEmails);
		mailJob.execute(mailQueue.getMailQueuePk());
		mailQueue = null; // free resource

	}

}
